package io.jpress.module.form.model;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Sets;
import com.jfinal.kit.Ret;
import com.jfinal.plugin.activerecord.Record;
import io.jboot.db.annotation.Table;
import io.jboot.utils.*;
import io.jpress.commons.UserAgentUtil;
import io.jpress.commons.utils.UrlUtils;
import io.jpress.module.form.model.base.BaseFormInfo;

import javax.servlet.http.HttpServletRequest;
import java.util.*;

/**
 * Generated by JPress.
 */
@Table(tableName = "form_info", primaryKey = "id")
public class FormInfo extends BaseFormInfo<FormInfo> {

    private static final long serialVersionUID = 1L;


    public static final String FORMINFO_STATUS_INIT = "init";
    public static final String FORMINFO_STATUS_PUBLISHED = "published";


    private static final Set<String> fieldTags = Sets.newHashSet("input", "textarea", "select"
            , "range", "radio", "checkbox", "date", "time", "datetime", "switch", "file-upload", "image-upload");


    /**
     * form_data_xx_xx 的默认字段
     */
    private static final Set<String> systemFields = Sets.newHashSet("id", "user_ip", "user_agent"
            , "user_browser", "user_browser_version", "user_os", "user_device", "user_device_brand", "user_network", "user_with_mobile", "user_start_time", "user_submit_time");


    private List<FieldInfo> fieldInfos;


    public String getUrl() {
        return UrlUtils.getUrl("/form/", getUuid());
    }


    public String getActionUrl() {
        return UrlUtils.getUrl("/form/postData/", getUuid());
    }


    public Record newRecord(Record oldRecord) {
        List<FieldInfo> fieldInfos = getFieldInfos();

        Record newRecord = new Record();

        systemFields.forEach(field -> {
            Object oldValue = oldRecord.get(field);
            newRecord.put(field, oldValue);
        });

        fieldInfos.forEach(fieldInfo -> {
            Object oldValue = oldRecord.get(fieldInfo.getFieldName());
            newRecord.put(fieldInfo.getFieldName(), fieldInfo.convertValueData(oldValue));
        });

        return newRecord;
    }


    public List<FieldInfo> getFieldInfos() {
        if (fieldInfos == null) {
            String json = getBuilderJson();
            JSONArray datas = JSON.parseArray(json);
            fieldInfos = new ArrayList<>();
            parseJsonArrayToDbFieldInfos(datas, fieldInfos);
        }
        return fieldInfos;
    }


    @Override
    public void setBuilderJson(String builderJson) {
        super.setBuilderJson(builderJson);
        fieldInfos = null;
    }

    public boolean isField(String fieldName) {
        List<FieldInfo> fieldInfos = getFieldInfos();
        for (FieldInfo fieldInfo : fieldInfos) {
            if (fieldName.equals(fieldInfo.getFieldName())) {
                return true;
            }
        }
        return false;
    }


    public Ret checkAllFields() {
        List<FieldInfo> fieldInfos = getFieldInfos();

        Set<String> errorLabels = new HashSet<>();
        for (FieldInfo dbFieldInfo : fieldInfos) {
            if (!dbFieldInfo.checkFieldStateOk()) {
                errorLabels.add(dbFieldInfo.getLabel());
            }
        }

        if (errorLabels.isEmpty()) {
            return Ret.ok();
        } else {
            return Ret.fail().set("message", CollectionUtil.toString(errorLabels, ",") + "的字段名不能为空，或者不能为纯数字。");
        }
    }


    public String toCreateTableSql() {
        //CREATE TABLE `form_dict_item` (
        //  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
        //  `text` text COMMENT '文本内容',
        //  `value` varchar(64) DEFAULT NULL COMMENT 'key',
        //  PRIMARY KEY (`id`)
        //) ENGINE=InnoDB AUTO_INCREMENT=43 DEFAULT CHARSET=utf8mb4;


        StringBuilder sqlBuilder = new StringBuilder();
        sqlBuilder.append("CREATE TABLE `").append(getCurrentTableName()).append("` (");
        sqlBuilder.append("`id` int(11) unsigned NOT NULL AUTO_INCREMENT,");

        List<FieldInfo> fieldInfos = getFieldInfos();
        for (FieldInfo fieldInfo : fieldInfos) {
            sqlBuilder.append(fieldInfo.toFieldSql()).append(",");
        }

        sqlBuilder.append("  `user_ip` varchar(64) DEFAULT NULL COMMENT '用户IP',\n" +
                "  `user_agent` varchar(512) DEFAULT NULL COMMENT '用户浏览器agent',\n" +
                "  `user_browser` varchar(64) DEFAULT NULL COMMENT '用户浏览器',\n" +
                "  `user_browser_version` varchar(64) DEFAULT NULL COMMENT '用户浏览器版本',\n" +
                "  `user_os` varchar(128) DEFAULT NULL COMMENT '用户操作系统',\n" +
                "  `user_device` varchar(128) DEFAULT NULL COMMENT '用户设备',\n" +
                "  `user_device_brand` varchar(128) DEFAULT NULL COMMENT '用户设备品牌',\n" +
                "  `user_network` varchar(32) DEFAULT NULL COMMENT '用户网络类型',\n" +
                "  `user_with_mobile` tinyint(1) DEFAULT NULL COMMENT '是否是手机',\n" +
                "  `user_start_time` datetime DEFAULT NULL COMMENT '用户开始时间',\n" +
                "  `user_submit_time` datetime DEFAULT NULL COMMENT '用户提交时间',\n");
        sqlBuilder.append("PRIMARY KEY (`id`)");
        sqlBuilder.append(") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;");

        return sqlBuilder.toString();
    }


    public Record parseRequestToRecord(HttpServletRequest request) {
        List<FieldInfo> fieldInfos = getFieldInfos();

        Record record = new Record();
        Map<String, String[]> parameters = request.getParameterMap();
        for (FieldInfo fieldInfo : fieldInfos) {
            String[] values = parameters.get(fieldInfo.getParaName());
            if (values != null && values.length > 0) {
                String paraValue = ArrayUtil.toString(values, ";");
                if (StrUtil.isBlank(paraValue)) {
                    if (fieldInfo.isRequired()) {
                        throw new IllegalArgumentException(fieldInfo.getLabel() + "数据不能为空！");
                    }
                    continue;
                }

                //检查数据长度
                if (!fieldInfo.checkValueLen(paraValue)) {
                    throw new IllegalArgumentException(fieldInfo.getLabel() + "数据长度过长！");
                }

                Object value;
                try {
                    value = fieldInfo.convertValueData(paraValue);
                } catch (Exception e) {
                    throw new IllegalArgumentException(e.getMessage(), e);
                }

                if (value != null) {
                    record.put(fieldInfo.getFieldName(), value);
                }
            }
        }

        Map<String, String> userAgentMap = UserAgentUtil.getUserAgentMap(request);

        record.set("user_ip", RequestUtil.getIpAddress(request));
        record.set("user_agent", RequestUtil.getUserAgent(request));
        record.set("user_browser", UserAgentUtil.getBrowserName(userAgentMap));
        record.set("user_browser_version", UserAgentUtil.getBrowserVersion(userAgentMap));
        record.set("user_os", UserAgentUtil.getOsName(userAgentMap));
        record.set("user_device", UserAgentUtil.getDeviceName(userAgentMap));
        record.set("user_device_brand", UserAgentUtil.getDeviceBrand(userAgentMap));
        record.set("user_network", UserAgentUtil.getNetworkType(userAgentMap));
        record.set("user_with_mobile", RequestUtil.isMobileBrowser(request));

        String userStartTime = request.getParameter("user_start_time");
        record.set("user_start_time", StrUtil.isBlank(userStartTime) ? null : ObjectUtil.convert(userStartTime, Date.class));

        record.set("user_submit_time", new Date());

        return record;
    }


    public String getCurrentTableName() {
        return "form_data_" + getId() + "_" + getVersion();
    }


    public String getPrevTableName() {
        return "form_data_" + getId() + "_" + (getVersion() - 1);
    }


    private void parseJsonArrayToDbFieldInfos(JSONArray datas, List<FieldInfo> fieldInfos) {
        if (datas == null || datas.isEmpty()) {
            return;
        }

        for (int i = 0; i < datas.size(); i++) {
            JSONObject data = datas.getJSONObject(i);

            JSONObject children = data.getJSONObject("children");

            //容器（布局组件）
            if (children != null) {
                for (String s : children.keySet()) {
                    parseJsonArrayToDbFieldInfos(children.getJSONArray(s), fieldInfos);
                }
            }

            //非布局组件数据
            else if (fieldTags.contains(data.getString("tag"))) {

                String fieldName = data.getString("field");
                String fieldType = data.getString("field_type");
                Integer fieldLenth = data.getInteger("field_lenth");

                FieldInfo fieldInfo = new FieldInfo();
                fieldInfo.setParaName(data.getString("name"));
                fieldInfo.setShowInList(data.getBoolean("show_list"));
                fieldInfo.setWithSearch(data.getBoolean("with_search"));
                fieldInfo.setFieldName(fieldName);
                fieldInfo.setFieldType(fieldType);
                fieldInfo.setFieldTypeLen(fieldLenth);
                fieldInfo.setLabel(data.getString("label"));
                fieldInfo.setTag(data.getString("tag"));
                fieldInfo.setRequired(data.getBoolean("required"));

                fieldInfos.add(fieldInfo);
            }
        }
    }


    public boolean isPublished() {
        return FORMINFO_STATUS_PUBLISHED.equals(getStatus());
    }


    @Override
    public String getBuilderJson() {
        String builderJson = super.getBuilderJson();
        return StrUtil.isNotBlank(builderJson) ? builderJson : "[]";
    }
}

